using System;
using System.Drawing;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace Elipsoid3D
{
    public partial class Form1 : Form
    {
        int total;
        int total2D = 10000;
        double percent = 1.0;
        int pie = 2;
        Vector2[] circle;
        Vector3[,] globe;
        private GLControl glControl1;
        private GLControl glControl2;

        private float[] materialDiffuseColor = { 1.0f, 0.0f, 0.0f, 1.0f };

        double zoom = 0.5;

        float[] p1 = { 2f, 2f, 2f, 2f };  //m,n1,n2,n3
        float[] ab1 = { 1.0f, 1.0f };            //a,b
        float[] p2 = { 2f, 2f, 2f, 2f };
        float[] ab2 = { 1.0f, 1.0f };

        private Vector2 lastMousePos;
        private float rotationX;
        private float rotationY;
        bool mousePressed = false; // Proměnná pro sledování stavu stisknutého tlačítka myši
        bool wasMousePressed = false;

        public Form1()
        {
            InitializeComponent();
            InitializeForm1();
            InitializeGLControl();
            panel1.Resize += panel1_Resize;
            this.Resize += Form1_Resize;
            globe = new Vector3[total + 1, total + 1];
            circle = new Vector2[total2D + 1];
            this.panel1.Controls.Add(glControl1);
            this.panel1.Controls.Add(glControl2);
            glControl2.Visible = false; // Skryj 2D vykreslování na začátku
            glControl1.Dock = DockStyle.Fill;
            glControl2.Dock = DockStyle.Fill;

            radioButton1.Checked = true;
            trackBar1.Value = 200;
            trackBar14.Value = 2;
            trackBar15.Value = 100;

            trackBar16.Value = 100;
            trackBar17.Value = 100;
            trackBar18.Value = 100;
        }

        private void panel1_Resize(object sender, EventArgs e)
        {
            glControl2.Size = new Size(panel1.ClientSize.Width, panel1.ClientSize.Height);
            glControl1.Size = new Size(panel1.ClientSize.Width, panel1.ClientSize.Height);
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            int panelWidth = this.ClientSize.Width / 2; // Šířka panelu je polovina šířky formuláře
            int panelHeight = (int)(this.ClientSize.Height * 0.9); // Výška panelu je 90% výšky formuláře

            panel1.Size = new Size(panelWidth, panelHeight); // Nastaví velikost panelu
        }

        private void InitializeForm1()
        {
            // Nastavení základních vlastností formuláře
            this.StartPosition = FormStartPosition.CenterScreen; // Nastaví formulář do středu obrazovky
            this.WindowState = FormWindowState.Maximized;
            this.Text = "Gielis Curve";
        }
        private void InitializeGLControl()
        {
            // Vytvoření GLControl a přidání eventů
            this.glControl1 = new OpenTK.GLControl();
            this.glControl2 = new OpenTK.GLControl();

            this.glControl1.Load += new System.EventHandler(this.GlControl1_Load);
            this.glControl1.Paint += new System.Windows.Forms.PaintEventHandler(this.GlControl1_Paint);

            this.glControl2.Load += new System.EventHandler(this.GlControl2_Load);
            this.glControl2.Paint += new System.Windows.Forms.PaintEventHandler(this.GlControl2_Paint);

            this.glControl1.MouseDown += GlControl1_MouseDown;
            this.glControl1.MouseMove += GlControl1_MouseMove;
            this.glControl1.MouseUp += GlControl1_MouseUp;
            this.glControl1.MouseWheel += GlControl1_MouseWheel;
            this.glControl2.MouseWheel += GlControl1_MouseWheel;
        }


        private void GlControl1_Load(object sender, EventArgs e)
        {
            GL.ClearColor(Color.FromArgb(20, 20, 20));
            GL.Enable(EnableCap.DepthTest);

            // Enable lighting
            GL.Enable(EnableCap.Lighting);
            GL.Enable(EnableCap.Light0);

            // Set up light properties
            float[] light_position = { 20, 20, 80, 1.0f }; // Light position
            float[] light_diffuse = { 1.0f, 1.0f, 1.0f, 1.0f }; // Light diffuse color
            float[] light_ambient = { 0.3f, 0.3f, 0.3f, 1.0f }; // Light ambient color
            float[] light_specular = { 1.0f, 1.0f, 1.0f, 1.0f }; // Light specular color

            GL.Light(LightName.Light0, LightParameter.Position, light_position);
            GL.Light(LightName.Light0, LightParameter.Diffuse, light_diffuse);
            GL.Light(LightName.Light0, LightParameter.Ambient, light_ambient);
            GL.Light(LightName.Light0, LightParameter.Specular, light_specular);

            // Set up material properties with red diffuse color
            float[] material_ambient = { 0.2f, 0.2f, 0.2f, 1.0f }; // Material ambient color
            float[] material_diffuse = { 1.0f, 0.0f, 0.0f, 1.0f }; // Red material diffuse color
            float[] material_specular = { 1.0f, 1.0f, 1.0f, 1.0f }; // Material specular color
            float   material_shininess = 30.0f; // Material shininess coefficient

            GL.Material(MaterialFace.Front, MaterialParameter.Ambient, material_ambient);
            GL.Material(MaterialFace.Front, MaterialParameter.Diffuse, material_diffuse);
            GL.Material(MaterialFace.Front, MaterialParameter.Specular, material_specular);
            GL.Material(MaterialFace.Front, MaterialParameter.Shininess, material_shininess);
        }

        private void GlControl2_Load(object sender, EventArgs e)
        {
            GL.ClearColor(Color.FromArgb(20, 20, 20));
            GL.Enable(EnableCap.DepthTest);
        }

        private void GlControl1_Paint(object sender, PaintEventArgs e)
        {
            glControl1.MakeCurrent();
            GL.Material(MaterialFace.Front, MaterialParameter.Diffuse, materialDiffuseColor);
            glControl1.SwapBuffers();
            Render3D(e);
        }

        private void GlControl2_Paint(object sender, PaintEventArgs e)
        {
            glControl2.MakeCurrent();
            glControl2.SwapBuffers();
            Render2D(e);
        }

        /////////////////////////////////////////////////////////////////   OVLADANI    ////////////////////////////////////////////////////////////////////////////////////

        private void GlControl1_MouseWheel(object sender, MouseEventArgs e)
        {
            // Získání informací o posunutí kolečkem myši
            int delta = e.Delta;

            // Přenastavení hodnoty rozsahu rotace podle směru pohybu kolečka myši
            if (delta > 0 && zoom < 1.0f) // Kolečko nahoru
            {
                zoom += 0.1f;
            }
            else if (delta < 0 && zoom > 0.1f) // Kolečko dolů
            {
                zoom -= 0.1f;
            }
        }

        private void GlControl1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                lastMousePos = new Vector2(e.X, e.Y);
                mousePressed = true;
            }
        }
        private void GlControl1_MouseMove(object sender, MouseEventArgs e)
        {
            if (mousePressed)
            {
                var mousePos = new Vector2(e.X, e.Y);
                var delta = mousePos - lastMousePos;
                rotationX += delta.Y * 0.01f;
                rotationY += delta.X * 0.01f;
                lastMousePos = mousePos;
            }
        }

        private void GlControl1_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                lastMousePos = Vector2.Zero;
                mousePressed = false;
            }
        }



        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



        private void Render2D(PaintEventArgs e)
        {
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            DrawGielis2D(zoom, e);
            glControl2.Invalidate();

        }
        private void Render3D(PaintEventArgs e)
        {
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            // Pouze rotace, když je stisknuto pravé tlačítko myši
            if (mousePressed)
            {
                GL.Rotate(rotationX, -1f, 0f, 0.0f);
                GL.Rotate(rotationY, 0f, -1f, 0.0f);
                wasMousePressed = true; // Nastavíme, že tlačítko bylo stisknuto
            }
            else if (wasMousePressed) // Pokud tlačítko bylo stisknuto a nyní není
            {
                rotationX = 0; // Nulujeme rotaci
                rotationY = 0;
                wasMousePressed = false; // Nastavíme, že tlačítko již není stisknuto
            }
            DrawGielis3D(zoom, e);
            glControl1.Invalidate();
        }

        private void CalculateGielis2D(int resolution, double p)
        {

            double[] u = GenerateArray(0, p*Math.PI, resolution);
            int maxLength = total2D * (int)percent;
            for (int i = 0; i <= u.Length-1; i++)
                {
                    double r = SuperShapeR(p1[0], p1[1], p1[2], p1[3], ab1[0], ab1[1], u, i);
                    double x = r * Math.Cos(u[i]);
                    double y = r * Math.Sin(u[i]);
                    circle[i] = new Vector2((float)x,(float)y);
                }
            Console.WriteLine("Calculated 2D");
        }

        private void CalculateGielis3D(int resolution, double p)
        {
            double[] u = GenerateArray(0, p * Math.PI, resolution);
            double[] v = GenerateArray(-Math.PI / 2.0, Math.PI / 2.0, resolution);
            for (int i = 0; i <= u.Length-1; i++)
            {
                for (int j = 0; j <= v.Length-1; j++)
                {
                    double r1 = SuperShapeR(p1[0], p1[1], p1[2], p1[3], ab1[0], ab1[1], u, i);
                    double r2 = SuperShapeR(p2[0], p2[1], p2[2], p2[3], ab2[0], ab2[1], v, j);
                    double x = r1 * Math.Cos(u[i]) * r2 * Math.Cos(v[j]);
                    double y = r1 * Math.Sin(u[i]) * r2 * Math.Cos(v[j]);
                    double z = r2 * Math.Sin(v[j]);
                    globe[i, j] = new Vector3((float)x, (float)y, (float)z);

                }
            }
            Console.WriteLine("Calculated 3D");
        }

        private void DrawGielis2D(double rt, PaintEventArgs e)
        {
                GL.LineWidth(2.5f);
                GL.Begin(PrimitiveType.Lines);

            for (int i = 0; i < total2D * percent; i++)
                {
                   Vector2 v1 = circle[i];
                   Vector2 v2 = circle[i+1];

                    GL.Vertex2(v1.X * rt, v1.Y * rt);
                    GL.Vertex2(v2.X * rt, v2.Y * rt);
                }
                GL.End();
          
        }

        private void DrawGielis3D(double rt, PaintEventArgs e)
        {
            for (int i = 0; i <= total*percent-1; i++)
            {
                GL.Begin(PrimitiveType.TriangleStrip);

                for (int j = 0; j <= total; j++)
                {
                    Vector3 v1 = globe[i, j];
                    Vector3 v2 = globe[i + 1, j];

                    // Phong lighting calculations
                    if (j == total)
                    {
                        Vector3 normal = CalculateNormal(globe[i, j - 1], globe[i, j], globe[i + 1, j - 1]);
                        GL.Normal3(normal);
                    }
                    else
                    {
                        Vector3 normal = CalculateNormal(globe[i, j], globe[i, j + 1], globe[i + 1, j]);
                        GL.Normal3(normal);
                    }

                    GL.Vertex3(v1.X * rt, v1.Y * rt, v1.Z * rt);
                    GL.Vertex3(v2.X * rt, v2.Y * rt, v2.Z * rt);
                }
                GL.End();
            }
        }


        static double SuperShapeR(double m, double n1, double n2, double n3, double a, double b, double[] angle, int i)
        {
            double rAngle = Math.Pow(Math.Abs(1 / a * Math.Abs(Math.Cos(m * angle[i] / 4.0))), n2) +
                            Math.Pow(Math.Abs(1 / b * Math.Abs(Math.Sin(m * angle[i] / 4.0))), n3);
            double r = Math.Pow(rAngle, (-1.0 / n1));
            return r;
        }

        static double[] GenerateArray(double start, double end, double cit)
        {
            double step = start - end;
            step /= cit;
            double[] vysledek = new double[(int)(cit + 1.0)];
            if (start == end)
            {
                for (int i = 0; i < vysledek.Length; i++)
                {
                    vysledek[i] = start;
                }
            }
            for (int i = 0; i < vysledek.Length; i++)
            {
                vysledek[i] = start;
                start -= step;
            }
            return vysledek;
        }


        private Vector3 CalculateNormal(Vector3 p0, Vector3 p1, Vector3 p2)
        {
            Vector3 normal = Vector3.Cross(p1 - p0, p2 - p0);
            return normal.Normalized();
        }




        ////////////////////////////////////////////////////////////////////////////  OVLADACI PRVKY  /////////////////////////////////////////////////////////////////////////


        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            total = (int)trackBar1.Value;
            globe = new Vector3[total + 1, total + 1];
            CalculateGielis2D(total2D, pie); 
            CalculateGielis3D(total, pie);

        }

        private void trackBar14_ValueChanged(object sender, EventArgs e)
        {

            pie = (int)trackBar14.Value;
            globe = new Vector3[total + 1, total + 1];
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar2_ValueChanged(object sender, EventArgs e)
        {
            label1.Text = (trackBar2.Value / 10.0).ToString();
            p1[0] = (float)(trackBar2.Value/10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);

        }

        private void trackBar3_ValueChanged(object sender, EventArgs e)
        {
            label2.Text = (trackBar3.Value / 10.0).ToString();
            p1[1] = (float)(trackBar3.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar4_ValueChanged(object sender, EventArgs e)
        {
            label3.Text = (trackBar4.Value / 10.0).ToString();
            p1[2] = (float)(trackBar4.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar5_ValueChanged(object sender, EventArgs e)
        {
            label4.Text = (trackBar5.Value / 10.0).ToString();
            p1[3] = (float)(trackBar5.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar10_ValueChanged(object sender, EventArgs e)
        {
            label24.Text = (trackBar10.Value / 10.0).ToString();
            ab1[0] = (float)(trackBar10.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar11_ValueChanged(object sender, EventArgs e)
        {
            label25.Text = (trackBar11.Value / 10.0).ToString();
            ab1[1] = (float)(trackBar11.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar6_ValueChanged(object sender, EventArgs e)
        {
            label5.Text = (trackBar6.Value / 10.0).ToString();
            p2[0] = (float)(trackBar6.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar7_ValueChanged(object sender, EventArgs e)
        {
            label6.Text = (trackBar7.Value / 10.0).ToString();
            p2[1] = (float)(trackBar7.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar8_ValueChanged(object sender, EventArgs e)
        {
            label7.Text = (trackBar8.Value / 10.0).ToString();
            p2[2] = (float)(trackBar8.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar9_ValueChanged(object sender, EventArgs e)
        {
            label8.Text = (trackBar9.Value / 10.0).ToString();
            p2[3] = (float)(trackBar9.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar12_ValueChanged(object sender, EventArgs e)
        {
            label26.Text = (trackBar12.Value / 10.0).ToString();
            ab1[0] = (float)(trackBar12.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void trackBar13_ValueChanged(object sender, EventArgs e)
        {
            label27.Text = (trackBar13.Value / 10.0).ToString();
            ab1[1] = (float)(trackBar13.Value / 10.0);
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            trackBar2.Value = 20;
            trackBar3.Value = 20;
            trackBar4.Value = 20;
            trackBar5.Value = 20;
            trackBar10.Value = 10;
            trackBar11.Value = 10;

            trackBar6.Value = 20;
            trackBar7.Value = 20;
            trackBar8.Value = 20;
            trackBar9.Value = 20;
            trackBar12.Value = 10;
            trackBar13.Value = 10;
            
        }

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton1.Checked)
            {
                glControl1.Visible = false;
                glControl2.Visible = true;
                CalculateGielis2D(total2D, pie);
                glControl2.Invalidate();

                trackBar6.Visible= false;
                trackBar7.Visible = false;
                trackBar8.Visible = false;
                trackBar9.Visible = false;
                trackBar12.Visible = false;
                trackBar13.Visible = false;

                label13.Visible = false;
                label14.Visible = false;
                label15.Visible = false;
                label16.Visible = false;
                label5.Visible = false;
                label6.Visible = false;
                label7.Visible = false;
                label8.Visible = false;
                label18.Visible = false;
                label30.Visible = false;
                label31.Visible = false;
                label26.Visible = false;
                label27.Visible = false;
            }

        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton2.Checked)
            {
                glControl2.Visible = false;
                glControl1.Visible = true;
                CalculateGielis3D(total, pie);
                glControl1.Invalidate();

                trackBar6.Visible = true;
                trackBar7.Visible = true;
                trackBar8.Visible = true;
                trackBar9.Visible = true;
                trackBar12.Visible = true;
                trackBar13.Visible = true;

                label13.Visible = true;
                label14.Visible = true;
                label15.Visible = true;
                label16.Visible = true;
                label5.Visible = true;
                label6.Visible = true;
                label7.Visible = true;
                label8.Visible = true;
                label18.Visible = true;
                label30.Visible = true;
                label31.Visible = true;
                label26.Visible = true;
                label27.Visible = true;
            }


        }

        private void trackBar15_ValueChanged(object sender, EventArgs e)
        {
            percent = trackBar15.Value/100.0;
            if (radioButton1.Checked) CalculateGielis2D(total2D, pie);
            if (radioButton2.Checked) CalculateGielis3D(total, pie);
        }



        private void trackBar16_ValueChanged(object sender, EventArgs e)
        {
            materialDiffuseColor[0] = trackBar16.Value / 100.0f; // R
        }

        private void trackBar17_ValueChanged(object sender, EventArgs e)
        {
            materialDiffuseColor[1] = trackBar17.Value / 100.0f; // G
        }

        private void trackBar18_ValueChanged(object sender, EventArgs e)
        {
            materialDiffuseColor[2] = trackBar18.Value / 100.0f; // B
        }
        private void button2_Click(object sender, EventArgs e)
        {
            trackBar2.Value = 50;
            trackBar3.Value = 1;
            trackBar4.Value = 17;
            trackBar5.Value = 17;
            trackBar10.Value = 10;
            trackBar11.Value = 10;

            trackBar6.Value = 10;
            trackBar7.Value = 3;
            trackBar8.Value = 5;
            trackBar9.Value = 5;
            trackBar12.Value = 10;
            trackBar13.Value = 10;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            trackBar2.Value = 30;
            trackBar3.Value = 80;
            trackBar4.Value = 350;
            trackBar5.Value = 360;
            trackBar10.Value = 10;
            trackBar11.Value = 10;

            trackBar6.Value = 80;
            trackBar7.Value = 200;
            trackBar8.Value = 80;
            trackBar9.Value = 100;
            trackBar12.Value = 10;
            trackBar13.Value = 10;
        }

        private void button4_Click(object sender, EventArgs e)
        {

            trackBar2.Value = 120;
            trackBar3.Value = 1000;
            trackBar4.Value = -1000;
            trackBar5.Value = 400;
            trackBar10.Value = 4;
            trackBar11.Value = 10;

            trackBar6.Value = 7;
            trackBar7.Value = 5;
            trackBar8.Value = 5;
            trackBar9.Value = 5;
            trackBar12.Value = 10;
            trackBar13.Value = 10;
        }
    }
}